/*****************************************************************************
* File Name: device.c
*
* Version: 1.0
*
* Description:
* This file contains API which integrate all the modules and the device 
* functionality in various power modes
*
* Note:
* None
*
* Owner: MRAO
*
* Related Document:
* None
*
* Hardware Dependency:
* None
*
* Code Tested With:
* 1. PSoC Creator 3.1 
* 2. ARM GCC 4.8.4
******************************************************************************
* Copyright (2015), Cypress Semiconductor Corporation.
******************************************************************************
* This software is owned by Cypress Semiconductor Corporation (Cypress) and is
* protected by and subject to worldwide patent protection (United States and
* foreign), United States copyright laws and international treaty provisions.
* Cypress hereby grants to licensee a personal, non-exclusive, non-transferable
* license to copy, use, modify, create derivative works of, and compile the
* Cypress Source Code and derivative works for the sole purpose of creating
* custom software in support of licensee product to be used only in conjunction
* with a Cypress integrated circuit as specified in the applicable agreement.
* Any reproduction, modification, translation, compilation, or representation of
* this software except as specified above is prohibited without the express
* written permission of Cypress.
*
* Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH
* REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 
* Cypress reserves the right to make changes without further notice to the
* materials described herein. Cypress does not assume any liability arising out
* of the application or use of any product or circuit described herein. Cypress
* does not authorize its products for use as critical components in life-support
* systems where a malfunction or failure may reasonably be expected to result in
* significant injury to the user. The inclusion of Cypress' product in a life-
* support systems application implies that the manufacturer assumes all risk of
* such use and in doing so indemnifies Cypress against all charges. Use may be
* limited by and subject to the applicable Cypress software license agreement.
*****************************************************************************/

#include "device.h"
#include "debug.h"
#include "watch_dog_timer.h"
#include "timer.h"
#include "led.h"
#include "audio.h"
#include "ir.h"
#include "keyboard.h"
#include "battery.h"
#include "button.h"
#include "ble.h"
#include "trackpad.h"
#include "motion_sensor.h"
#include "flash.h"

/* Variable for the modules to raise the event */
DeviceEvent deviceEvent;

#ifndef DISABLE_FLASH
#if defined(__GNUC__) || defined(__ARMCC_VERSION)
static const uint8 appUserFlashData[CY_FLASH_SIZEOF_ROW] CYBLE_FLASH_ROW_ALIGNED =
#elif defined(__ICCARM__)
#pragma data_alignment = CY_FLASH_SIZEOF_ROW
static const uint8 appUserFlashData[CY_FLASH_SIZEOF_ROW ] CYBLE_FLASH_ROW_ALIGNED  =
#endif /* defined(__GNUC__) || defined(__ARMCC_VERSION) */
{
    0xFF, 0x1
};
#endif /* DISABLE_FLASH */

Flash_Data flashDataInRam;
bool writeFlashData = false;

#if (DEVICE_UNDIRECTED_ADV_THRESHOLD > 0) && (DEVICE_DIRECTED_ADV_THRESHOLD >  0)
static uint8 directedAdvCount = 0, unDirectedAdvCount = 0;
#endif /* (DEVICE_UNDIRECTED_ADV_THRESHOLD > 0) && (DEVICE_DIRECTED_ADV_THRESHOLD >  0) */ 

static bool isAdvertisementStarted;
/* Variables knowing the previous button status */
static uint8 prevButtonStatus = 0;

static uint8 batteryState = BATTERY_MONITORING_ABOVE_VOLTAGE;
extern uint8 trackpad_gesture_code;
extern uint8 trackpad_send_nocode;
static void Device_Battery_Monitoring(bool forceBatteryVoltage);
/*****************************************************************************
* Function Name: Device_Init()
******************************************************************************
* Summary:
* This function initializes various modules
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* This API checks for low battery. If battery is above the threshold then 
* initializes all the modules 
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
void Device_Init(void)
{
    /* Trim Values for the crystal */
    CY_SET_XTND_REG32((void CYFAR *)(CYREG_BLE_BLERD_BB_XO_CAPTRIM), LOAD_CAP_VALUE);
    Battery_Init();
    Device_Battery_Monitoring(true);
    if(batteryState == BATTERY_MONITORING_CUT_OFF_VOLTAGE)
    {
        DEVICE_LOW_BATTERY_DETECTED();
        Led_Init();
        Device_Led_Slow_Blinking();
        /* Wait until the Low Battery is detected and a LED blink is provided for the User */
        while(!Device_Led_BlinkComplete())
        {
            Watch_Dog_Timer_Clear();
            CySysPmSleep();
        }
    }
    else
    {
#ifndef DISABLE_FLASH
        Flash_Load(appUserFlashData,(uint8 *)&flashDataInRam, sizeof(Flash_Data));
#endif /* DISABLE_FLASH */
        Ble_Init();
        Motion_Sensor_Init();
        Led_Init();
        Audio_Init();
        IR_Init(Device_IR_Address);
        Keyboard_Init();
        Button_Init();
        Trackpad_Init();

        /* Ble_Init functionality needs to be checked here */
        do
        {
            Ble_ProcessEvents();
        }while(!Ble_Is_Init_Completed());
        Ble_Configure();
        Device_Led_Fast_Blinking();
#ifdef DISABLE_KEYBOARD
        Ble_StartAdvertisement(false, false);
#endif /* DISABLE_KEYBOARD */
    }
}

/*****************************************************************************
* Function Name: Device_Battery_Voltage_Percentage()
******************************************************************************
* Summary:
* This function calculates the battery percentage
*
* Parameters:
* None
*
* Return:
* uint8 - Battery value in percentage. Valid range is 0 - 100
*
* Theory:
* The formula used for the calculation is as follows
* %Value = (Current Battery voltage - Min Battery value)/(Max Battery value - Min Battery Value)
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
static uint8 Device_Battery_Voltage_Percentage(uint16 batteryVoltage)
{
    uint8 batteryVoltagePercentage;
    if(batteryVoltage < DEVICE_BATTERY_CUT_OFF_VOLTAGE)
    {
        batteryVoltage = DEVICE_BATTERY_LOW_VOLTAGE;
    }
    else if(batteryVoltage > DEVICE_BATTERY_MAX_VOLTAGE)
    {
         batteryVoltage = DEVICE_BATTERY_MAX_VOLTAGE;
    }
    batteryVoltage = batteryVoltage - DEVICE_BATTERY_CUT_OFF_VOLTAGE;
    batteryVoltagePercentage = (uint8)((100 * batteryVoltage)/(DEVICE_BATTERY_MAX_VOLTAGE - DEVICE_BATTERY_CUT_OFF_VOLTAGE));
    return batteryVoltagePercentage;
}

/*****************************************************************************
* Function Name: Device_Battery_Monitoring()
******************************************************************************
* Summary:
* This function performs the battery monitoring for the device
*
* Parameters:
* bool forceBatteryVoltage - To force the battery module to perform battery monitoring 
*                            else battery monitoring can be performed every 3 seconds
*
* Return:
* None
*
* Theory:
* This API gets the current battery value from the battery module and checks 
* for low battery voltage and cutoff voltage. It keeps reporting the various battery 
* values to the BLE central devices
*
* Side Effects:
* batteryState variable is updated with the status of the battery 
* 
* Note:
* None
*****************************************************************************/
static void Device_Battery_Monitoring(bool forceBatteryVoltage)
{
    /* Variables for battery monitoring */
    static uint32 batteryTimeStamp = 0;
    static uint8 prevBatteryVoltagePercentage = DEVICE_INITIAL_BATTERY_LEVEL;
#ifdef ENABLE_HARDWARE_WORKAROUND_MINIPROG
    static bool isMiniProgConnected = false;
#endif /* ENABLE_HARDWARE_WORKAROUND_MINIPROG */
    uint16 batteryVoltage,batteryVoltagePercentage;
    if(Timer_Time_Elapsed(batteryTimeStamp, DEVICE_BATTERY_SCAN_TIME_MS) || forceBatteryVoltage)
    {
#ifdef ENABLE_HARDWARE_WORKAROUND_MINIPROG
        if(isMiniProgConnected)
        {
            Battery_No_Battery_Connected(true);
            CyDelay(1);
        }
#endif /* ENABLE_HARDWARE_WORKAROUND_MINIPROG */
        batteryVoltage = Battery_Get_Value();
        batteryTimeStamp = Timer_Get_Time_Stamp();
        batteryState = BATTERY_MONITORING_ABOVE_VOLTAGE;
        batteryVoltagePercentage = Device_Battery_Voltage_Percentage(batteryVoltage);
#ifndef DEVICE_BATTERY_PARALLEL
        if(prevBatteryVoltagePercentage > batteryVoltagePercentage)
#else
        if((prevBatteryVoltagePercentage > batteryVoltagePercentage) || \
                    ((prevBatteryVoltagePercentage + DEVICE_BATTERY_THRESHOLD) < batteryVoltagePercentage)
#endif /* DEVICE_BATTERY_PARALLEL */
        {
            if(Ble_Send_Battery_Data(batteryVoltagePercentage))
            {
                prevBatteryVoltagePercentage = batteryVoltagePercentage;
            }
        }

        if(batteryVoltage < (uint16)DEVICE_NO_BATTERY_MINIPROG_CONNECTED)
        {
#ifdef ENABLE_HARDWARE_WORKAROUND_MINIPROG
            Battery_No_Battery_Connected(false);
            isMiniProgConnected = true;
#endif /* ENABLE_HARDWARE_WORKAROUND_MINIPROG */
            /* If no battery is connected and powered with miniprog, a pull up is required */
        }
        else
        {
#ifdef ENABLE_HARDWARE_WORKAROUND_MINIPROG
            isMiniProgConnected = false;
#endif /* ENABLE_HARDWARE_WORKAROUND_MINIPROG */
            if(batteryVoltage < (uint16)DEVICE_BATTERY_CUT_OFF_VOLTAGE)
            {   
                batteryState = BATTERY_MONITORING_CUT_OFF_VOLTAGE;
            }
            else if(batteryVoltage < (uint16)DEVICE_BATTERY_LOW_VOLTAGE)
            {
                batteryState = BATTERY_MONITORING_LOW_VOLTAGE;
            }
        }
    }
}

/*****************************************************************************
* Function Name: Device_Active_Poll()
******************************************************************************
* Summary:
* This function polls all the modules
*
* Parameters:
* None
*
* Return:
* bool - True if battery voltage is less than the cutoff voltage
*
* Theory:
* The polls for audio module or trackpad module or motion sensor module depending 
* upon the button status. By default it keeps calling the ble_Process event for 
* processing the BLE events 
*
* Side Effects:
* prevButtonStatus is updated
* 
* Note:
* None
*****************************************************************************/
static bool Device_Active_Poll(void)
{
    uint8 buttonStatus;
    bool buttonStatusChanged = false;
    Watch_Dog_Timer_Clear();
    Ble_ProcessEvents();
#ifdef DISABLE_MOTION_SENSOR
    /* To Remove Warning */
    (void)buttonStatusChanged;
#endif /* DISABLE_MOTION_SENSOR */
    buttonStatus = Button_Poll();
    if(prevButtonStatus != buttonStatus)
    {
        buttonStatusChanged = true;
        if(((!(buttonStatus & MOTION_SENSOR_BUTTON_MASK)) && (prevButtonStatus & MOTION_SENSOR_BUTTON_MASK)) || 
               (buttonStatus & VOICE_BUTTON_MASK))
        {
            prevButtonStatus &= ~MOTION_SENSOR_BUTTON_MASK;
            Motion_Sensor_Stop_Sampling();  
            if(!(buttonStatus & VOICE_BUTTON_MASK))
              Debug_Print(DEBUG_MESSAGE_LEVEL_4,"Motion Sensor Stop\r\n");
        }
        else if((buttonStatus & MOTION_SENSOR_BUTTON_MASK) && (!(prevButtonStatus & MOTION_SENSOR_BUTTON_MASK)))
        {
            prevButtonStatus |= MOTION_SENSOR_BUTTON_MASK;
            Motion_Sensor_Start_Sampling();
            Debug_Print(DEBUG_MESSAGE_LEVEL_4,"Motion Sensor Start\r\n");
        }

        if(!(buttonStatus & VOICE_BUTTON_MASK) && (prevButtonStatus & VOICE_BUTTON_MASK))
        {
            /* Restore the clocks from different modules if required */
            prevButtonStatus &= ~VOICE_BUTTON_MASK;
            Audio_Stop();
#ifdef AUDIO_RUN_ON_ECO
            CySysClkImoStart();
            CySysClkWriteHfclkDirect(CY_SYS_CLK_HFCLK_IMO);
            Ble_DisableLowPowerMode(false);
#endif /* AUDIO_RUN_ON_ECO */
            //Audio_Poll();
            Ble_Disconnect_Audio_Channel();
            Trackpad_Reset();
        }
        else if((buttonStatus & VOICE_BUTTON_MASK) && (!(prevButtonStatus & VOICE_BUTTON_MASK)))
        {
            if(Ble_Create_Audio_Channel())
            {
#ifdef AUDIO_RUN_ON_ECO
                /* Add clock change from different modules if switch freq is occurring 
                 * from different modules 
                 */
                Ble_ExitLPM();
                Ble_DisableLowPowerMode(true);
                CySysClkWriteHfclkDirect(CY_SYS_CLK_HFCLK_ECO);
                CySysClkImoStop();
#endif /* AUDIO_RUN_ON_ECO */
                prevButtonStatus |= VOICE_BUTTON_MASK;
                Audio_Start();
            }
            else
            {
                if(!isAdvertisementStarted && ((Ble_Get_State() != BLE_STATE_CONNECTED) && \
                                                        (Ble_Get_State() != BLE_STATE_CONNECTED_PATH_LOSS)))
                {
                    /* Enable the line "if(Ble_Get_State() == BLE_STATE_DISCONNECTED_LINK_LOSS)" and disable 
                     * "if(Ble_IsValidPeerAddressPresent())" if you need to blink only when there is a link loss 
                     * and not explict disconnection from the centeral side
                     */
                    /* if(Ble_Get_State() == BLE_STATE_DISCONNECTED_LINK_LOSS) */
                    if(Ble_IsValidPeerAddressPresent())
                    {
                        Device_Led_Fast_Blinking();
                    }

                    if(Ble_IsValidPeerAddressPresent())
                    {
#if (DEVICE_DIRECTED_ADV_THRESHOLD >  0) && (DEVICE_UNDIRECTED_ADV_THRESHOLD > 0)
                        if(directedAdvCount >= DEVICE_DIRECTED_ADV_THRESHOLD)
                        {
                            if(Ble_StartAdvertisement(false, true) == BLE_ADVERTISE_STARTED)
                            {
                                unDirectedAdvCount++;
                                if(unDirectedAdvCount >= DEVICE_UNDIRECTED_ADV_THRESHOLD)
                                {
                                    directedAdvCount = 0;
                                }
                            }
                        }
                        else
                        {
                            if(Ble_StartAdvertisement(true, false) == BLE_ADVERTISE_STARTED)
                            {
                                unDirectedAdvCount = 0;
                                directedAdvCount++;    
                            }
                        }
#elif (DEVICE_UNDIRECTED_ADV_THRESHOLD > 0)
                        Ble_StartAdvertisement(false, true);
#elif (DEVICE_DIRECTED_ADV_THRESHOLD >  0)
                        Ble_StartAdvertisement(true, false);
#endif /* (DEVICE_DIRECTED_ADV_THRESHOLD >  0) && (DEVICE_UNDIRECTED_ADV_THRESHOLD > 0) */
                    }
                }
            }
        }

        
    }

    if((prevButtonStatus & VOICE_BUTTON_MASK))
    {
        Audio_Poll();
        Device_Battery_Monitoring(false);
    }
    else
    {
        if(prevButtonStatus & MOTION_SENSOR_BUTTON_MASK)
        {
            Keyboard_Poll();
            Motion_Sensor_Poll(buttonStatusChanged | Keyboard_IsButtonStatusChanged());
            Debug_Print(DEBUG_MESSAGE_LEVEL_3, "Motion Sensor Poll\r\n");
        }
        else
        {
            Trackpad_Start_Poll();
            Keyboard_Poll();
        }
        
        Device_Battery_Monitoring(false);
        while(!Trackpad_IsComplete())
        {
            CySysPmSleep();
        }
         /* Put BLE in low power mode  */
        Ble_Enter_LowPowerMode();
        Trackpad_Poll();
        Ble_Enter_LowPowerMode();
    }
    if(trackpad_gesture_code)
      Debug_Print(DEBUG_MESSAGE_LEVEL_3,"trackpad_gesture_code = %d\r\n",trackpad_gesture_code);
    /*  Check if the BLE advertisement is completed and turn off the LED on completion */
    if(Ble_IsAdvertisingCompleted() && isAdvertisementStarted)
    {
        isAdvertisementStarted = false;
        Led_Stop();
				Debug_Print(DEBUG_MESSAGE_LEVEL_4,"Device_Led_Advert_stop\r\n");
        if(Ble_Get_State() == BLE_STATE_CONNECTED)
        {
            Device_Led_Connected();
        }
    }
    return (batteryState != BATTERY_MONITORING_CUT_OFF_VOLTAGE);
}

/*****************************************************************************
* Function Name: Device_Low_Power_Poll()
******************************************************************************
* Summary:
* This function polls the modules which cannot interrupt the mcu to
* notify activity
*
* Parameters:
* None
*
* Return:
* bool - True if battery voltage is less than the cutoff voltage
*
* Theory:
* Poll trackpad module and button modules as these modules cannot interrupt 
* the system
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
static bool Device_Low_Power_Poll(void)
{
    Watch_Dog_Timer_Clear();
    Ble_ProcessEvents();
    /* Trackpad Poll is going occur only in the Active and Idle mode */
    if(!(prevButtonStatus & MOTION_SENSOR_BUTTON_MASK))
    {
        Trackpad_Start_Poll();
        Button_Poll();
        Device_Battery_Monitoring(false);
        while(!Trackpad_IsComplete())
        {
            CySysPmSleep();
        }
        Trackpad_Poll();
    }
    else
    {
        /* Enable this code if motion sensor need to be polled */
        /* MotionSensor_IsMotionDetectedLowPower();  */ 
        Button_Poll();
        Device_Battery_Monitoring(false);
    }
    return (batteryState != BATTERY_MONITORING_CUT_OFF_VOLTAGE);;
}

/*****************************************************************************
* Function Name: Device_Get_Report()
******************************************************************************
* Summary:
* This function collects the report from various modules
*
* Parameters:
* Report *report - Structure that need to be filled up
*
* Return:
* ReportType - Type of report that is filled by the module
*
* Theory:
* 
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
static ReportType Device_Get_Report(Report *report)
{
    ReportType report_type = NO_REPORT;
    report_type |= Button_Get_Report(report);
    report_type |= Keyboard_Get_Report(report);
    report_type |= Audio_Get_Report(report);    
    report_type |= Trackpad_Get_Report(report);
    report_type |= Motion_Sensor_Get_Report(report);
    if(writeFlashData)
    {
#ifndef DISABLE_FLASH
        Flash_Save((uint8 *)&flashDataInRam, (uint8 *)appUserFlashData, sizeof(Flash_Data));
#endif /* DISABLE_FLASH */
        writeFlashData = false;
    }
    return report_type;
}

/*****************************************************************************
* Function Name: Device_IsActivity()
******************************************************************************
* Summary:
* This function checks if any further activity can be detected by the modules
*
* Parameters:
* None
*
* Return:
* bool - true if activity can be detected
*
* Theory:
* Checks if the module is active or not
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
static bool Device_IsActivity(bool forDeepSleep)
{
    bool result = false;
    if(!forDeepSleep)
    {
        result |= Keyboard_IsActive();        
        result |= Trackpad_IsActive();
        result |= Button_IsActive();
        result |= Motion_Sensor_IsActive();
    }
    result |= Audio_IsActive();
    result |= (!Device_Led_BlinkComplete());
    return result;
}

/*****************************************************************************
* Function Name: Device_Send_Data()
******************************************************************************
* Summary:
* This function sends the data to the output modules  
*
* Parameters:
* ReportType report_type - Type of the report that need to be sent
* Report *report - Report structure which contains data to be sent
*
* Return:
* None
*
* Theory:
* Sends the data over BLE if connected, else sends the data over IR. If pair 
* button is pressed then BLE advertisement is called 
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
static void Device_Send_Data(ReportType report_type, Report *report)
{
    uint8 advertisingState;
    if(Keyboard_IsPairButtonDown())
    {
        advertisingState = Ble_StartAdvertisement(false, false);
        Debug_Print(DEBUG_MESSAGE_LEVEL_3,"Ble_StartAdvertisement false false\r\n");
        if((advertisingState == BLE_ADVERTISE_STARTED) || \
                                (advertisingState == BLE_ADVERTISE_ALREADY_STARTED))
        {
            isAdvertisementStarted = true;
            //Device_Led_On_Continous();
            if(!Device_Led_BlinkComplete())
            {
              Device_Led_Stop();
            }
            Device_Led_Adverting();
        }
    }
    //isPairButtonPressed = false;
    isPairButtonDown = false;
    if((report_type != NO_REPORT) &&  (batteryState == BATTERY_MONITORING_LOW_VOLTAGE))
    {
        //Device_Led_Stop();
        Device_Led_Slow_Blinking();
    }

    if((Ble_Get_State() == BLE_STATE_CONNECTED) || (Ble_Get_State() == BLE_STATE_CONNECTED_PATH_LOSS))
    {
        /* Blink the LED on path loss */
        if((report_type != NO_REPORT) && (Ble_Get_State() == BLE_STATE_CONNECTED_PATH_LOSS))
        {
            Device_Led_Fast_Blinking();
        }
        Ble_Send_Data(report_type,report);
#if (DEVICE_UNDIRECTED_ADV_THRESHOLD > 0) && (DEVICE_DIRECTED_ADV_THRESHOLD >  0)
        directedAdvCount = 0;
        unDirectedAdvCount = 0;
#endif /* (DEVICE_UNDIRECTED_ADV_THRESHOLD > 0) && (DEVICE_DIRECTED_ADV_THRESHOLD >  0)*/
    }
    else
    {
        if(!isAdvertisementStarted && report_type != NO_REPORT)
        {
            /* Enable the line "if(Ble_Get_State() == BLE_STATE_DISCONNECTED_LINK_LOSS)" and disable 
             * "if(Ble_IsValidPeerAddressPresent())" if you need to blink only on link loss 
             * and not on explict disconnection from the centeral side
             */

            /* if(Ble_Get_State() == BLE_STATE_DISCONNECTED_LINK_LOSS) */
            if(Ble_IsValidPeerAddressPresent())
            {
                Device_Led_Fast_Blinking();
            }
            //Debug_Print(DEBUG_MESSAGE_LEVEL_3,"Ble_IsValidPeerAddressPresent\r\n");
            if(Ble_IsValidPeerAddressPresent())
            {
#if (DEVICE_DIRECTED_ADV_THRESHOLD >  0) && (DEVICE_UNDIRECTED_ADV_THRESHOLD > 0)
                if(directedAdvCount >= DEVICE_DIRECTED_ADV_THRESHOLD)
                {
                    if(Ble_StartAdvertisement(false, true) == BLE_ADVERTISE_STARTED)
                    {
                        unDirectedAdvCount++;
                        if(unDirectedAdvCount >= DEVICE_UNDIRECTED_ADV_THRESHOLD)
                        {
                            directedAdvCount = 0;
                        }
                    }
                }
                else
                {
                    if(Ble_StartAdvertisement(true, false) == BLE_ADVERTISE_STARTED)
                    {
                        unDirectedAdvCount = 0;
                        directedAdvCount++;    
                    }
                }
#elif (DEVICE_UNDIRECTED_ADV_THRESHOLD > 0)
                Ble_StartAdvertisement(false, true);
#elif (DEVICE_DIRECTED_ADV_THRESHOLD >  0)
                Ble_StartAdvertisement(true, false);
#endif /* (DEVICE_DIRECTED_ADV_THRESHOLD >  0) && (DEVICE_UNDIRECTED_ADV_THRESHOLD > 0) */
            }
        }
        IR_Start(&report->ir_report);
        while(!IR_Complete())
        {
            CySysPmSleep();
        }
    }
}

/*****************************************************************************
* Function Name: Device_Set_State()
******************************************************************************
* Summary:
* This function sets the state for all the modules
*
* Parameters:
* Device_State state - state to which all the modules need to switched to
*
* Return:
* None
*
* Theory:
* Depending upon the state all the modules can enter the low power or active state 
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
static void Device_Set_State(Device_State state)
{
    Motion_Sensor_Set_State(state);
    Keyboard_Set_State(state);
    Trackpad_Set_State(state);
    Button_Set_State(state);
    Ble_Set_State(state);
}

/*****************************************************************************
* Function Name: Device_Active()
******************************************************************************
* Summary:
* This function defines the behaviour for the device in active state(DEVICE_ACTIVE)
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* Device is expected to be in active mode until the there is any user activity. 
* Device leaves this mode after a no activity timeout
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
void Device_Active(void)
{
    uint32 timeStamp,activityTimeStamp;
    Report report;
    ReportType report_type = NO_REPORT;
    bool isActivity;
    bool isDatasent = false;
    Device_Set_State(DEVICE_ACTIVE);
    timeStamp = Timer_Get_Time_Stamp();
    activityTimeStamp = timeStamp;
    while(!Timer_Time_Elapsed(activityTimeStamp,DEVICE_ACTIVE_TIMEOUT))
    {
        if(!Device_Active_Poll())
        {
            DEVICE_LOW_BATTERY_DETECTED();
            /* Wait for the Led Blinking to be complete before entering shut down */
            while(!Device_Led_BlinkComplete())
            {
                CySysPmSleep();
            }
            return;
        }
        if((deviceEvent==0)&&(trackpad_send_nocode))
        {
          Debug_Print(DEBUG_MESSAGE_LEVEL_3, "trackpad_send_nocode\r\n");
          trackpad_send_nocode = false;
          trackpad_gesture_code = 6;
          DEVICE_POST_EVENT(TRACKPAD_EVENT);
        }
        if(deviceEvent)
        {            
            memset(&report,0, sizeof(Report));        
            report.ir_report.command = INVALID;
            report_type = Device_Get_Report(&report);
        }
        isActivity = Device_IsActivity(true);
        while(!Timer_Time_Elapsed(timeStamp,TIME_BETWEEN_TWO_POLL_ACTIVE))
        {
            /* Sync Mechanism */
            if(Ble_Enter_LowPowerMode() && !isActivity )
            {
#ifndef MCU_DEEP_SLEEP_DISABLED
#ifndef DISABLE_BLE
                CyGlobalIntDisable;
                if((CyBle_GetBleSsState() == CYBLE_BLESS_STATE_ECO_ON) || (CyBle_GetBleSsState() == CYBLE_BLESS_STATE_DEEPSLEEP))
#endif /* DISABLE_BLE */
                {
                    CySysPmDeepSleep();              
                }
#ifndef DISABLE_BLE
                CyGlobalIntEnable;
#endif /* DISABLE_BLE */
#else
                CySysPmSleep(); 
#endif /* MCU_DEEP_SLEEP_DISABLED */
            }
            else
            {
#ifndef DISABLE_BLE
                if(CyBle_GetBleSsState() == CYBLE_BLESS_STATE_ECO_STABLE)
                {
                    if(deviceEvent)
                    {
                        Debug_Print(DEBUG_MESSAGE_LEVEL_3,"deviceEvent = 0x%x\r\n",deviceEvent);
                        timeStamp = Timer_Get_Time_Stamp();
                        isDatasent = true;
                        Device_Send_Data(report_type, &report);
                        deviceEvent = NO_EVENT;
                    }
                    break;
                }
                else if(CyBle_GetBleSsState() != CYBLE_BLESS_STATE_EVENT_CLOSE)
#endif /* DISABLE_BLE */
                {
                    CySysPmSleep();
                }
            }
        }
        
        if(!isDatasent)
        {
            timeStamp = Timer_Get_Time_Stamp();
            if(deviceEvent)
            {
                Device_Send_Data(report_type, &report);
                deviceEvent = NO_EVENT;
            }
        }
        isDatasent = false;
        isActivity = Device_IsActivity(false);
        if(report_type || isActivity)
        {
            activityTimeStamp = timeStamp;
            report_type = NO_REPORT;
        }
        
        if(!Device_IsActivity(true))
        {
            Ble_WriteBondedList();
            if(writeFlashData)
            {
#ifndef DISABLE_FLASH
                Flash_Save((uint8 *)&flashDataInRam, (uint8 *)&appUserFlashData, sizeof(Flash_Data));
#endif /* DISABLE_FLASH */
                writeFlashData = false;
            }
        }
    }
}

/*****************************************************************************
* Function Name: Device_Low_Power_State()
******************************************************************************
* Summary:
* This function defines the behaviour for the device in low power state(DEVICE_IDLE, 
* DEVICE_SLEEP and DEVICE_DEEPSLEEP state)
*
* Parameters:
* Device_State state - current device state 
* uint32 lowPowerTimeOut - Time out that it is required to be in that state
* uint32 timeBetweenTwoPoll - Time between two polls 
*
* Return:
* None
*
* Theory:
* Device is expected to be in active mode until the there is any user activity. 
* Device leaves this mode after no-activity timeout
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
void Device_Low_Power_State(Device_State state, uint32 lowPowerTimeOut, uint32 timeBetweenTwoPoll)
{
    uint32 activityTimeStamp, timeStamp;
#ifndef DISABLE_BLE
    CYBLE_BLESS_STATE_T blessState;
#endif /* DISABLE_BLE */

    Device_Set_State(state);
    activityTimeStamp = Timer_Get_Time_Stamp();
    timeStamp = activityTimeStamp;
    Ble_WriteBondedList();
		Debug_Print(DEBUG_MESSAGE_LEVEL_4,"Device_Low_Power_State =%d\r\n",state);
    while(!Timer_Time_Elapsed(activityTimeStamp,lowPowerTimeOut) && !isActitiyDetected)
    {
        if(!Device_Low_Power_Poll())
        {
            DEVICE_LOW_BATTERY_DETECTED();
            
            /* Wait for the LED blinking to complete before entering shut down */
            while(!Device_Led_BlinkComplete())
            {
                Watch_Dog_Timer_Clear();
                CySysPmSleep();
            }
            break;
        }

        while(!Timer_Time_Elapsed(timeStamp,timeBetweenTwoPoll) && !isActitiyDetected)
        {
            Watch_Dog_Timer_Clear();
            if(Ble_Enter_LowPowerMode())
            {
#ifndef MCU_DEEP_SLEEP_DISABLED
#ifndef DISABLE_BLE
                CyGlobalIntDisable;
                blessState = CyBle_GetBleSsState();
                if((blessState == CYBLE_BLESS_STATE_ECO_ON) || (blessState == CYBLE_BLESS_STATE_DEEPSLEEP))
#endif /* DISABLE_BLE */
                {
                    
                    CySysPmDeepSleep();
                }
#ifndef DISABLE_BLE
                CyGlobalIntEnable;
#endif /* DISABLE_BLE */
#else
                CySysPmSleep();
#endif /* MCU_DEEP_SLEEP_DISABLED */
            }
            else
            {
#ifndef DISABLE_BLE
                CyGlobalIntDisable;
                blessState = CyBle_GetBleSsState();
                if((blessState != CYBLE_BLESS_STATE_EVENT_CLOSE))
#endif /* DISABLE_BLE */
                {
#ifndef DISABLE_BLE
                    if(blessState != CYBLE_BLESS_STATE_ECO_STABLE)
#endif /* DISABLE_BLE */
                    {
                        CySysClkWriteHfclkDirect(CY_SYS_CLK_HFCLK_ECO);
                        CySysClkImoStop();
                        CySysPmSleep();
                        CySysClkImoStart();
                        CySysClkWriteHfclkDirect(CY_SYS_CLK_HFCLK_IMO);
                        CyGlobalIntEnable;
                    }
#ifndef DISABLE_BLE
                    else
                    {
                        CyGlobalIntEnable;
                        break;
                    }
#endif /* DISABLE_BLE */
                }
#ifndef DISABLE_BLE
                CyGlobalIntEnable;
#endif /* DISABLE_BLE */
            }
        }
        timeStamp = Timer_Get_Time_Stamp();
    }
    Ble_ProcessEvents();
}

/*****************************************************************************
* Function Name: Device_ShutDown()
******************************************************************************
* Summary:
* This function defines the behaviour for the device in stop state (DEVICE_STOP)
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* All the modules are stopped
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
void Device_ShutDown(void)
{
    Keyboard_Stop();
    Button_Stop();
    Motion_Sensor_Stop();
    Battery_Stop();
    Audio_Stop();
    Trackpad_Stop();
    Led_Stop();
    IR_Stop();
    Ble_Stop();
}

/*****************************************************************************
* Function Name: Device_Timer_Callback()
******************************************************************************
* Summary:
* This function is called when a timer interrupt occurs. This function can 
* be used to update any parameter with the tick of timer. Currently it is used 
* to update the Led Module to provide the Breathing Led effect
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* Update the LED parameters on every timer tick
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
void Device_Timer_Callback(void)
{
    Led_Update();
    if(Device_Led_BlinkComplete())
    {
        Timer_CallBack_Disable();
    }
}
